Passed
Push — master ( 616dea...d489a6 )
by Kolja
02:44
created

jgfJsonDecorator.js ➔ fromJson   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 2
nop 1
dl 0
loc 16
rs 9.95
c 0
b 0
f 0
1
const _ = require('deepdash')(require('lodash'));
2
const check = require('check-types');
3
const { JgfNode } = require('./jgfNode');
4
const { JgfEdge } = require('./jgfEdge');
5
const { JgfGraph } = require('./jgfGraph');
6
const { JgfMultiGraph } = require('./jgfMultiGraph');
7
8
/**
9
 * Transforms graphs or multi graphs to json or vice versa.
10
 *
11
 * Note that this is just called decorator for semantic reasons and does not follow and does not intend to follow
12
 * the GoF decorator design pattern.
13
 */
14
class JgfJsonDecorator {
15
16
    /**
17
     * Creates a Jgf graph or multi graph from JSON.
18
     * @param {object} json JSON to be transformed to a graph or multigraph. This has to be according to the JGF.
19
     * @throws Error if json can not be transformed to a graph or multi graph.
20
     * @returns {JgfGraph|JgfMultiGraph} The created Jgf graph or multi graph object.
21
     */
22
    static fromJson(json) {
23
        if (check.assigned(json.graph)) {
24
            return this._graphFromJson(json.graph);
25
        }
26
27
        if (check.assigned(json.graphs)) {
28
            let graph = new JgfMultiGraph(json.type, json.label, json.metadata);
29
            _.each(json.graphs, (graphJson) => {
30
                graph.addGraph(this._graphFromJson(graphJson))
31
            });
32
33
            return graph;
34
        }
35
36
        throw new Error('Passed json has to to have a "graph" or "graphs" property.');
37
    }
38
39
    /**
40
     * Creates a single JGF graph from JSON.
41
     * @param {object} graphJson
42
     * @returns {JgfGraph}
43
     * @private
44
     */
45
    static _graphFromJson(graphJson) {
46
        let graph = new JgfGraph(graphJson.type, graphJson.label, graphJson.directed, graphJson.metadata);
47
48
        _.each(graphJson.nodes, (node) => {
49
            graph.addNode(new JgfNode(node.id, node.label, node.metadata));
50
        });
51
52
        _.each(graphJson.edges, (edge) => {
53
            graph.addEdge(new JgfEdge(edge.source, edge.target, edge.relation, edge.label, edge.metadata, edge.directed));
54
        });
55
56
        return graph;
57
    }
58
59
    static _guardAgainstInvalidGraphObject(graph) {
60
        if (!check.instance(graph, JgfGraph) && !check.instance(graph, JgfMultiGraph)) {
61
            throw new Error('JgfJsonDecorator can only decorate graphs or multi graphs.');
62
        }
63
    }
64
65
    /**
66
     * Transforms either a graph or a multi graph object to a JSON representation as per the spec.
67
     * @param {JgfGraph|JgfMultiGraph} graph The graph to be transformed to JSON.
68
     * @throws Error if the passed graph or multi graph can not be transformed to JSON.
69
     * @returns {object} A JSON representation of the passed graph or multi graph as according to the JGF.
70
     */
71
    static toJson(graph) {
72
        this._guardAgainstInvalidGraphObject(graph);
73
74
        const isSingleGraph = check.instance(graph, JgfGraph);
75
76
        let allGraphsJson = {
77
            graphs: [],
78
        };
79
80
        this._transformGraphsToJson(graph, allGraphsJson);
81
82
        if (isSingleGraph) {
83
            return this._removeNullValues({ graph: allGraphsJson.graphs[0] });
84
        }
85
86
        allGraphsJson.type = graph.type;
87
        allGraphsJson.label = graph.label;
88
        allGraphsJson.metadata = graph.metadata;
89
90
        return this._removeNullValues(allGraphsJson);
91
    }
92
93
    static _transformGraphsToJson(graph, allGraphsJson) {
94
        let normalizedGraph = this._normalizeToMultiGraph(graph);
95
        _.each(normalizedGraph.graphs, (singleGraph) => {
96
97
            let singleGraphJson = {
98
                type: singleGraph.type,
99
                label: singleGraph.label,
100
                directed: singleGraph.directed,
101
                metadata: singleGraph.metadata,
102
                nodes: [],
103
                edges: [],
104
            };
105
106
            this._nodesToJson(singleGraph, singleGraphJson);
107
            this._edgesToJson(singleGraph, singleGraphJson);
108
109
            allGraphsJson.graphs.push(singleGraphJson);
110
        });
111
    }
112
113
    static _removeNullValues(json) {
114
        return _.filterDeep(json, (value) => value !== null);
115
    }
116
117
    /**
118
     * @param {JgfGraph} graph
119
     * @param {object} json
120
     * @private
121
     */
122
    static _edgesToJson(graph, json) {
123
        _.each(graph.edges, (edge) => {
124
            json.edges.push({
125
                source: edge.source,
126
                target: edge.target,
127
                relation: edge.relation,
128
                label: edge.label,
129
                metadata: edge.metadata,
130
                directed: edge.directed,
131
            });
132
        });
133
    }
134
135
    /**
136
     * @param {JgfGraph} graph
137
     * @param {object} json
138
     * @private
139
     */
140
    static _nodesToJson(graph, json) {
141
        _.each(graph.nodes, (node) => {
142
            json.nodes.push({
143
                id: node.id,
144
                label: node.label,
145
                metadata: node.metadata,
146
            });
147
        });
148
    }
149
150
    static _normalizeToMultiGraph(graph) {
151
        let normalizedGraph = graph;
152
        if (check.instance(graph, JgfGraph)) {
153
            normalizedGraph = new JgfMultiGraph();
154
            normalizedGraph.addGraph(graph);
155
        }
156
157
        return normalizedGraph;
158
    }
159
}
160
161
module.exports = {
162
    JgfJsonDecorator,
163
};